﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows;

namespace Urbini.Fabio._5BI.BattagliaNavale
{
    // Problema nel metodo RandomPosizione(Posizioni PosizioniCliccate)
    // Quando sono già state cliccate tante posizioni, può essere lanciata un'eccezione di StackOverflow (il metodo viene richiamato troppe volte)
    public class Global
    {
        public const int MAX_CELLE = 64;
        public const int RIGHE = 8;
        public const int COLONNE = 8;
        // VARIABILI DI CONTROLLO
        public const int NaviDaUno = 1;
        public const int NaviDaDue = 2;
        public const int NaviDaTre = 2;
        public const int NaviDaQuattro = 1;
        public static Dictionary<TipoNave, int> NaviMax = new Dictionary<TipoNave, int>()
        {
            { TipoNave.DaUno, NaviDaUno},
            { TipoNave.DaDue, NaviDaDue},
            {TipoNave.DaTre, NaviDaTre},
            {TipoNave.DaQuattro, NaviDaQuattro}
        };
        /// <summary>
        /// Questo metodo può essere utile per aggiornare i bottoni
        /// </summary>
        /// <param name="btn"></param>
        /// <param name="Stato"></param>
        public static void StatoColore(Button btn, StatoCella stato)
        {
            switch (stato)
            {
                // Per barare cambiare il colore di StatoCella.InvisibilePresente
                case StatoCella.NonDefinito: btn.Background = Brushes.WhiteSmoke; break;
                case StatoCella.Acqua: btn.Background = Brushes.Aqua; break;
                case StatoCella.Colpita: btn.Background = Brushes.Red; break;
                case StatoCella.Affondata: btn.Background = Brushes.Black; break;
                case StatoCella.NavePresente: btn.Background = Brushes.Green; break;
                case StatoCella.InvisibilePresente: btn.Background = Brushes.WhiteSmoke; break;
            }
        }
        public static void AggiornaColoreBottoni(Grid GridPosizionamentoNavi, Giocatore giocatore, bool MappaVistaDaGiocatore)  
        {
            // Scorrimento di tutti gli elementi contenuti nel Grid
            foreach (UIElement Element in GridPosizionamentoNavi.Children)
            {
                Button b = Element as Button;
                if (b != null)
                {
                    int x = Convert.ToInt32(b.Tag.ToString().Split(';')[0]);
                    int y = Convert.ToInt32(b.Tag.ToString().Split(';')[1]);
                    Posizione posizione = new Posizione(x, y);
                    // T1
                    // Qui ho il bottone della mappa iniziale. Avendo la x e la y, devo cercar lo stesso bottone nella nuova grid
                    Global.StatoColore(b, (giocatore.mappa.MappaGiocatore(MappaVistaDaGiocatore))[posizione.Indice].Stato);
                }
            }
        }
        /// <summary>
        /// Assegna i tag (x;y) a ogni bottone
        /// </summary>
        /// <param name="GridMappa"></param>
        public static void AssegnaTag(Grid GridMappa)
        {
            // Metodo per l'assegnazione dei tag ai bottoni
            int idx = 0;
            foreach (UIElement ui in GridMappa.Children)
            {
                Button b = ui as Button;
                if (b != null)
                {
                    b.Tag = (idx % 8).ToString() + ";" + (idx / 8).ToString();
                    idx++;
                }
            }
        }
        /// <summary>
        /// Disabilita tutti i bottoni della mappa del giocatore
        /// </summary>
        /// <param name="GridMappaGiocatore"></param>
        public static void DisabilitaBottoniGrid (Grid GridMappaGiocatore)
        {
            foreach (UIElement ui in GridMappaGiocatore.Children)
            {
                Button b = ui as Button;
                if (b != null)
                {
                    b.IsEnabled = false;
                }
            }
        }
    }
    /// <summary>
    /// Finire metodo RandomFlotta()
    /// </summary>
    public static class FlottaTools
    {
        /// <summary>
        /// Restituisce una posizione casuale
        /// </summary>
        /// <returns></returns>
        public static Posizione RandomPosizione()
        {
            // Questo metodo genera una coordinata casuale senza controlli.
            Random temp = new Random(DateTime.Now.Millisecond);
            int Indice = temp.Next(0, (Global.COLONNE * Global.RIGHE )- 1);
            return new Posizione(Indice);
        }
        public static Posizione RandomPosizione(Posizioni PosizioniCliccate)
        {
            Random temp = new Random(DateTime.Now.Millisecond);
            int Indice = temp.Next(0, (Global.COLONNE * Global.RIGHE) - 1);
            Posizione p = new Posizione(Indice);

            foreach (Posizione prova in PosizioniCliccate)
                if (p.Indice == prova.Indice) return RandomPosizione(PosizioniCliccate);
            return new Posizione(Indice);
        }
        /// <summary>
        /// Restituisce una direzione casuale
        /// </summary>
        /// <returns></returns>
        public static DirezioneNave RandomDirezione()
        {
            Random temp = new Random(DateTime.Now.Millisecond);
            return (DirezioneNave)temp.Next(1, 4);
        }
        public static Flotta RandomFlotta()
        {
            Flotta flotta = new Flotta();
            List<int> IndiciGenerati = new List<int>();

            // Generare n navi da uno. Controllare la classe global.
            for (int i = 0; i < Global.NaviDaUno; i++)
            {
                List<int> Indici = FlottaTools.GeneraIndici(1, IndiciGenerati);
                Posizioni Posizioni = new Posizioni(Indici);
                Nave nave = new Nave(Posizioni);
                flotta.Add(nave);
            }
            for (int i = 0; i < Global.NaviDaDue; i++)
            {
                // Controllare e copiare le istruzioni qui sopra
                List<int> Indici = FlottaTools.GeneraIndici(2, IndiciGenerati);
                Posizioni Posizioni = new Posizioni(Indici);
                Nave nave = new Nave(Posizioni);
                flotta.Add(nave);
            }
            for (int i = 0; i < Global.NaviDaTre; i++)
            {
                List<int> Indici = FlottaTools.GeneraIndici(3, IndiciGenerati);
                Posizioni Posizioni = new Posizioni(Indici);
                Nave nave = new Nave(Posizioni);
                flotta.Add(nave);
            }
            for (int i = 0; i < Global.NaviDaQuattro; i++)
            {
                List<int> Indici = FlottaTools.GeneraIndici(4, IndiciGenerati);
                Posizioni Posizioni = new Posizioni(Indici);
                Nave nave = new Nave(Posizioni);
                flotta.Add(nave);
            }
            return flotta;
        }
        public static List<int> IndiciGenerati (DirezioneNave Direzione, Posizione posizione, TipoNave Tipo)
        {
            List<int> Indici = new List<int>();
            Posizione posizioneI = posizione;
            int grandezza = (int)Tipo;

            // Se è data una direzione
            if (Direzione != 0)
            {
                Indici.AddRange(GetIndiciByPosizioneIniziale(grandezza, Direzione, posizioneI));
            }
            return Indici;
        }

        /// <summary>
        /// Indica se il numero dato in input è contenuto in una lista di numeri interi
        /// </summary>
        /// <param name="num"></param>
        /// <param name="IndiciGenerati"></param>
        /// <returns></returns>
        public static bool IsNumContained(int num, List<int> IndiciGenerati)
        {
            foreach (int value in IndiciGenerati)
                if (value == num) return true;

            return false;
        }
        /// <summary>
        /// Indica se gli indici dati in Input sono permessi
        /// </summary>
        /// <param name="Indici"></param>
        /// <param name="IndiciGenerati"></param>
        /// <returns></returns>
        /// 

        private static Posizione GetPosizione(DirezioneNave Direzione, Posizione Posizione)
        {
            Posizione posizione = new Posizione(Posizione.X, Posizione.Y);
            switch (Direzione)
            {
                case DirezioneNave.Sinistra: posizione.X--; break;
                case DirezioneNave.Su: posizione.Y--; break;
                case DirezioneNave.Destra: posizione.X++; break;
                case DirezioneNave.Giu: posizione.Y++; break;
                default: return null;
            }
            if (posizione.PosizioneValida(Global.RIGHE - 1, Global.COLONNE - 1)) return posizione;
            return null;
        }
        public static bool IndiciPermessi(List<int> Indici, List<int> IndiciGenerati)
        {
            foreach (int i in Indici)
                foreach (int k in IndiciGenerati)
                    if (i == k) return false;
            return true;
        }
        public static List<int> GetIndiciByPosizioneIniziale(int Grandezza, DirezioneNave d, Posizione p)
        {
            List<int> IndiciGenerati = new List<int>();
            Posizione p1 = new Posizione(p.X, p.Y);

            for (int i = 0; i < Grandezza; i++)
            {
                IndiciGenerati.Add(p1.Indice);
                p1 = GetPosizione(d, p1);
                if (p1 == null) return null;
            }

            return IndiciGenerati;
        }
        public static List<int> GeneraIndici(int Grandezza, List<int> IndiciGenerati)
        {
            bool continua = true;
            List<int> Indici = new List<int>();

            while (continua)
            {
                DirezioneNave direzione = RandomDirezione();
                Posizione posizioneIniziale = RandomPosizione();
                Indici = GetIndiciByPosizioneIniziale(Grandezza, direzione, posizioneIniziale);
                // Se la Lista di Indici è nulla, è avvenuto un errore.
                if (Indici != null)
                    if (IndiciPermessi(Indici, IndiciGenerati))
                        continua = false;
            }
            IndiciGenerati.AddRange(Indici);
            return Indici;
        }
    }
}
